#
 # 	odump.S
 #
 #  Author      : 84236   90110   90131
#
#include <mips/regdef.h>
#include <sys/syscall.h>
#include "DefinicionIndicesErrores.h"
#define CERO 		48					# ascii del cero para tener una referencia

#define SSIZE		(32)
#define	O_RA		(24)
#define	O_FP		(20)
#define	O_GP		(16)
#define O_ARG0		32
#define O_ARG1		36
#define O_ARG2		40
#define BUFFER		0
#define VECTOR		1
#define CONTADOR	4
#define LONGITUD_DELIMITADOR	8

			.text
			.align 	2
			.globl	odump_encode
			.ent	odump_encode

odump_encode:
			.frame 	$fp,SSIZE,ra
   			.set  	noreorder
   			.cpload t9
   			.set  	reorder

   			# creo stack frame
   			subu	sp,sp,SSIZE
			sw		gp,O_GP(sp)
			sw		$fp,O_FP(sp)
			sw		ra,O_RA(sp)
			move	$fp,sp
			sw		a0,O_ARG0($fp)
			sw		a1,O_ARG1($fp)
			sw		a2,O_ARG2($fp)

			# calculo longitud del delimitador
			lw		t0,O_ARG2($fp)
			lw		a0,4(t0)
			la		t9,my_strlen
			jal		ra,t9
			sw		v0,LONGITUD_DELIMITADOR($fp)

			# inicializo contador para longitud por linea
			sw		zero,CONTADOR($fp)

			#cargo s2  que marca un fin de lectura por stdin. 1 marca fin
			li s2,0

			#verifico si la entrada es por stdin
			lw t7,O_ARG0($fp)
			bne t7,zero,leer1byte

			#cargo s1 con 1 que indica que se esta leyendo por stdin
			li s1,1

leer1byte:
			li		v0,SYS_read
			lw		a0,O_ARG0($fp)		# a0 = infd
			la		a1,BUFFER($fp)		# a1 = direccion de BUFFER
			li		a2,1				# a2 = 1 byte
			syscall

			# verifico EOF y errores
			beq		v0,zero,ejecucion_correcta_encode	# si v0=0 es EOF
		 	bne		a3,zero,error_lectura_encode	# si a3!=0 hay un error
		 	bne		v0,1,error_lectura_encode		# si no leyo 1 byte hay un error

		 	#verifico si se lee por  stdin
		 	bne s1,1,procesarByte

validarFinStdin:
			#verifico si el ultimo leido es salto de linea
			#cargo en t8 el newline
			li t8,0
			lb t8,newLine
			#cargo en t7 el ultimo byte leido
			li t7,0
			la t7,BUFFER($fp)
			lb t7,0(t7)

			#si son iguales no debo leer mas bytes, sino sigo normal
			bne t7,t8,procesarByte

			#si era new line marco el fin de lectura de stdin
			li s2,1

			#Quite esto para que el salto de línea sea incluido en el archivo de salida
			#salto a la escritura del delimitador
			#b	escribirDelimitador

procesarByte:
			# aumento contador
			lw		t6,CONTADOR($fp)	# t6 = CONTADOR
			addiu	t6,t6,1				# t6 = CONTADOR + 1
			sw		t6,CONTADOR($fp)	# CONTADOR = t6

			li 		t0,CERO 			# t0 = CERO
			la 		t1,BUFFER($fp)		# t1 = direccion del BUFFER
			lb 		t1,0(t1) 			# t1 = *BUFFER
			li 		t2,0 				# t2 contador
			la		t3,VECTOR($fp)		# t3 = direccion del VECTOR
			addiu	t3,t3,2				# aumento 2 posiciones para grabar de atras para adelante

loopCalculo:
			beq		t2,3,escribirOctal	# si contador=3 ya hizo los calculos
			remu 	t4,t1,8 			# t4 = t1 mod 8
			addu 	t4,t4,t0 			# t4 += CERO
			sb 		t4,0(t3) 			# VECTOR[t3] = calculo del resto
			divu 	t1,t1,8				# t1 = t1/8
			subu 	t3,t3,1 			# decremento indice vector
			addiu 	t2,t2,1 			# incremento contador
			b 		loopCalculo			# salta a loopCalculo

escribirOctal:
			# escribe el octal
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		# a0 = outfd
			la		a1,VECTOR($fp)		# a1 = direccion de VECTOR
			li		a2,3				# a2 = 3 bytes
			syscall

			# verifico de errores de escritura
			bne		v0,3,error_escritura_encode		# si no escribio 3 bytes hay un error

escribirDelimitador:
			# escribe el delimitador
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		# a0 = outfd
			lw		t0,O_ARG2($fp)		# t0 = odump_pts
			lw		a1,4(t0)			# a1 = direccion de delimitador
			lw		a2,LONGITUD_DELIMITADOR($fp)	# a2 = longitud delimitador
			syscall

			# verifico de errores de escritura
			lw		t0,LONGITUD_DELIMITADOR($fp)	# t0 = longitud delimitador
		 	bne		v0,t0,error_escritura_encode	# si no escribio la cantidad de bytes del delimitador hay error

saltoDeLinea:
			# calculo si hay que hacer salto de linea
			lw		t0,O_ARG2($fp)		# t0 = odump_pts
			lw		t0,0(t0)			# t0 = length
			beq		t0,zero,proximoByte	# length=0 -> proximoByte
			lw		t1,CONTADOR($fp)	# t1 = CONTADOR
			bne		t0,t1,proximoByte	# lenght!=CONTADOR -> proximoByte

			# si llego aca es porque hay que escribir el salto de linea
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		# a0 = outfd
			la		a1,newLine			# a1 = direccion de newLine
			li		a2,1				# a2 = 1 byte
			syscall

			# verifico de errores de escritura
			bne		v0,1,error_escritura_encode		# si no escribio 1 byte hay un error

			# vuelvo a inicializar CONTADOR
			sw		zero,CONTADOR($fp)

proximoByte:

			# si es stdin y se leyo ya el salto de linea es fin
			beq  s2,1,fin_odump_encode

			# vuelvo a leer el siguiente byte
			b leer1byte

error_lectura_encode:
			li		v0,ERROR_LECTURA
			b		fin_odump_encode

error_escritura_encode:
			li		v0,ERROR_ESCRITURA
			b		fin_odump_encode

ejecucion_correcta_encode:
			li		v0,EJECUCION_CORRECTA

fin_odump_encode:
			# destruyo stack frame
			move	sp,$fp
			lw		gp,O_GP(sp)
			lw		$fp,O_FP(sp)
			lw		ra,O_RA(sp)
			addiu	sp,sp,SSIZE
			jr		ra
			.end	odump_encode

			.data
newLine:
			.ascii 	"\n"
error_encode:
			.ascii	"Se ha producido un error\n"

############################################################################

			.text
			.align 	2
			.globl	odump_decode
			.ent	odump_decode

odump_decode:
			.frame 	$fp,SSIZE,ra
 			.set 	noreorder
 			.cpload t9
 			.set 	reorder

 			# creo stack frame
  			subu	sp,sp,SSIZE
			sw		gp,O_GP(sp)
			sw		$fp,O_FP(sp)
			sw		ra,O_RA(sp)
			move	$fp,sp
			sw		a0,O_ARG0($fp)
			sw		a1,O_ARG1($fp)
			sw		a2,O_ARG2($fp)

			#calculo longitud del delimitador
			lw		t0,O_ARG2($fp)
			lw		a0,4(t0)
			la		t9,my_strlen
			jal		ra,t9
			sw		v0,LONGITUD_DELIMITADOR($fp)

leer3bytes:
			# leo primer byte
			li		v0,SYS_read
			lw		a0,O_ARG0($fp)		# a0 = infd
			la		a1,VECTOR($fp)		# a1 = direccion de VECTOR
			li		a2,1				# a2 = 1 bytes
			syscall

			# verifico EOF y errores
			beq		v0,zero,ejecucion_correcta_decode	# si v0=0 es EOF
		 	bne		a3,zero,error_lectura_decode	# si a3!=0 hay un error
		 	bne		v0,1,error_lectura_decode		# si no leyo 1 byte hay un error

		 	# si no es un salto de linea leo el segundo y tercer byte
		 	lb		t0,VECTOR($fp)
		 	lb		t1,newLine				# t1 = \n
			bne		t0,t1,leerSegundo_y_TercerByte

			# si es un salto de linea verifico si el archivo esta dado por stdin
			lw		t0,O_ARG0($fp)		# t0 = infd
			bne		t0,1,leer3bytes
			b		fin_odump_decode

leerSegundo_y_TercerByte:
			# leo segundo byte
			li		v0,SYS_read
			lw		a0,O_ARG0($fp)		# a0 = infd
			addiu	a1,$fp,1
			la		a1,VECTOR(a1)
			li		a2,2				# a2 = 2 bytes
			syscall

			# verifico EOF y errores
			beq		v0,zero,ejecucion_correcta_decode	# si v0=0 es EOF
		 	bne		a3,zero,error_lectura_decode	# si a3!=0 hay un error
		 	bne		v0,2,error_lectura_decode		# si no leyo 2 bytes hay un error

			# calculos para obtener el binario
			li 		t0,CERO 			# t0 = CERO
			li		t4,73
			mul		t0,t0,t4			# t0 = CERO*73
			la 		t5,VECTOR($fp)		# t5 = direccion del VECTOR
			lb 		t1,0(t5) 			# t1 = *VECTOR[0]
			lb 		t2,1(t5) 			# t2 = *VECTOR[1]
			lb 		t3,2(t5) 			# t3 = *VECTOR[2]
			li		t4,64
			mul		t1,t1,t4			# t1 = t1*64
			li		t4,8
			mul		t2,t2,t4			# t2 = t2*8
			addu	t1,t1,t2			# t1 = t1 + t2
			addu	t1,t1,t3			# t1 = t1 + t3
			subu	t1,t1,t0			# t1 = t1 - t0
			sb 		t1,BUFFER($fp) 		# BUFFER = t1

escribirBinario:
			# escribe el binario
			li		v0,SYS_write
			lw		a0,O_ARG1($fp)		# a0 = outfd
			la		a1,BUFFER($fp)		# a1 = direccion de BUFFER
			li		a2,1				# a2 = 1 byte
			syscall

			# verifico de errores de escritura
			bne		v0,1,error_escritura_decode	# si no escribio 1 byte hay error

			#s0: puntero a raiz delimitador
			#s1: indice
			#s2: longitud delimitador
			#t0: byte leido del archivo
			#t1: byte del delimitador parametro
			#t2: auxiliar
			lw		s2,LONGITUD_DELIMITADOR($fp)
			beq		s2,zero,leer3bytes
			lw		s0,O_ARG2($fp)
			lw		s0,4(s0)
			li		s1,0

verificarDelimitador:
			beq		s1,s2,leer3bytes
			li		v0,SYS_read
			lw		a0,O_ARG0($fp)		# a0 = infd
			la		a1,BUFFER($fp)
			li		a2,1				# a2 = 1 bytes
			syscall

			# verifico EOF y errores
			beq		v0,zero,ejecucion_correcta_decode	# si v0=0 es EOF
		 	bne		a3,zero,error_lectura_decode	# si a3!=0 hay un error
		 	bne		v0,1,error_lectura_decode		# si no leyo 1 byte hay un error

			# comparacion
			lb	 	t0,BUFFER($fp)
			addu	t2,s0,s1
			lb		t1,0(t2)
			subu	t2,t0,t1
			bne		zero,t2,error_delimitador_decode
			addiu	s1,s1,1
			b		verificarDelimitador

			# vuelvo a leer los 3 siguientes bytes
			b 		leer3bytes			# salta a leer3bytes

error_lectura_decode:
			li		v0,ERROR_LECTURA
			b		fin_odump_decode

error_escritura_decode:
			li		v0,ERROR_ESCRITURA
			b		fin_odump_decode

error_delimitador_decode:
			li		v0,ERROR_DELIMITADORES
			b		fin_odump_decode

ejecucion_correcta_decode:
			li		v0,EJECUCION_CORRECTA

fin_odump_decode:
			# destruyo stack frame
			move	sp,$fp
			lw		gp,O_GP(sp)
			lw		$fp,O_FP(sp)
			lw		ra,O_RA(sp)
			addiu	sp,sp,SSIZE
			jr		ra
			.end	odump_decode

#define SSIZE_ERROR			(16)
#define	O_RA_ERROR			(12)
#define	O_FP_ERROR			(8)
#define	O_GP_ERROR			(4)
			.text
			.align 	2
			.globl	inicializarError
			.ent	inicializarError

inicializarError:
			.frame 	$fp,SSIZE_ERROR,ra
   			.set  	noreorder
   			.cpload t9
   			.set  	reorder

   			# creo stack frame
   			subu	sp,sp,SSIZE_ERROR
			sw		gp,O_GP_ERROR(sp)
			sw		$fp,O_FP_ERROR(sp)
			sw		ra,O_RA_ERROR(sp)
			move	$fp,sp

finInicializarError:
			# destruyo stack frame
			move	sp,$fp
			lw		gp,O_GP_ERROR(sp)
			lw		$fp,O_FP_ERROR(sp)
			lw		ra,O_RA_ERROR(sp)
			addiu	sp,sp,SSIZE_ERROR
			jr		ra
			.end	inicializarError

			.rdata
			.extern ejecucion_correcta
ejecucion_correcta:
			.asciiz	"Ejecución correcta"
			.extern	error_lectura
error_lectura:
			.asciiz	"ERROR en lectura"
			.extern	error_escritura
error_escritura:
			.asciiz	"ERROR en escritura"
			.extern	error_delimitador
error_delimitador:
			.asciiz	"ERROR delimitador incorrecto"
			.extern error_argumentos_incorrectos
error_argumentos_incorrectos:
			.asciiz	"ERROR argumentos incorrectos"
			.extern	odump_errmsg
			.align 2
odump_errmsg:
	.word	ejecucion_correcta, error_lectura, error_delimitador, error_argumentos_incorrectos
